/*
* This runs a tarantula algorithm to determine the fault in the function score for.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <math.h>
#include <assert.h>
#include "dominion.h"
#include "dominion_helpers.h"
#include "rngs.h"
#include "GameStateSanitizer.h"


#define VERBOSE 0

#define NUM_RAND_TESTS 2000

//the number of lines in the function to be tested
#define NUM_LINES 23  

int lastRunLines[NUM_LINES];  //the lines that were run on the last run of the function
			     //1 or more if the line was run and 0 otherwise


int runOnSuccess[NUM_LINES]; //the number of times a line was run on a successfull run

int runOnFailure[NUM_LINES]; //the number of times a line was run on failure

int suspiciousness[NUM_LINES];  //the suspiciouness of a line

int successRuns = 0;  //the number of successful runs
int failRuns = 0;  //the number of failed runs


/* sets the value of lastRunLines to zero in preperation for the next run */
void zeroLastRunLines() {
	int i;
	for (i = 0; i < NUM_LINES; i++)
		lastRunLines[i] = 0;
}

/* adds the number of times each last run was run to runOnSuccess[] */
void addSuccess() {
	int i;
	for (i = 0; i < NUM_LINES; i++)
		runOnSuccess[i] += lastRunLines[i];
}

/* adds the number of times each last run was run to runOnFailure[] */
void addFailures() {
	int i;
	for (i = 0; i < NUM_LINES; i++)
		runOnFailure[i] += lastRunLines[i];
}

/* calculates the suspiciousness of lines using the formula:
	suspiciousness(e) = (failed(e)/failRuns) / (passed(e)/successRuns + failed(e)/failRuns)) */
void calculateSuspiciousness() {
	assert(failRuns != 0);
	assert(successRuns != 0);

	int i;
	for (i = 0; i < NUM_LINES; i++) {
		suspiciousness[i] = 100 * (runOnFailure[i] / (double) failRuns) / ((runOnSuccess[i] / (double) successRuns) + (runOnFailure[i] / (double) failRuns));
	}
}


/* Prints out the calculated suspiciousness of each line */
void printSuspiciousness() {
printf("%d%%\tint i;\n", suspiciousness[0]);
printf("%d%%\tint score = 0;\n", suspiciousness[1]);
printf("\t//score from hand\n");
printf("%d%%\tfor (i = 0; i < state->handCount[player]; i++)\n", suspiciousness[2]);
printf("\t{\n");
printf("%d%%\t\tif (state->hand[player][i] == curse) { score = score - 1; };\n", suspiciousness[3]);
printf("%d%%\t\tif (state->hand[player][i] == estate) { score = score + 1; };\n", suspiciousness[4]);
printf("%d%%\t\tif (state->hand[player][i] == duchy) { score = score + 3; };\n", suspiciousness[5]);
printf("%d%%\t\tif (state->hand[player][i] == province) { score = score + 6; };\n", suspiciousness[6]);
printf("%d%%\t\tif (state->hand[player][i] == great_hall) { score = score + 1; };\n", suspiciousness[7]);
printf("%d%%\t\tif (state->hand[player][i] == gardens) { score = score + ( fullDeckCount(player, 0, state) / 10 ); };\n", suspiciousness[8]);
printf("\t}\n");
printf("\n");
printf("\t//score from discard\n");
printf("%d%%\tfor (i = 0; i < state->discardCount[player]; i++)\n", suspiciousness[9]);
printf("\t{\n");
printf("%d%%\t\tif (state->discard[player][i] == curse) { score = score - 1; };\n", suspiciousness[10]);
printf("%d%%\t\tif (state->discard[player][i] == estate) { score = score + 1; };\n", suspiciousness[11]);
printf("%d%%\t\tif (state->discard[player][i] == duchy) { score = score + 3; };\n", suspiciousness[12]);
printf("%d%%\t\tif (state->discard[player][i] == province) { score = score + 6; };\n", suspiciousness[13]);
printf("%d%%\t\tif (state->discard[player][i] == great_hall) { score = score + 1; };\n", suspiciousness[14]);
printf("%d%%\t\tif (state->discard[player][i] == gardens) { score = score + ( fullDeckCount(player, 0, state) / 10 ); };\n", suspiciousness[15]);
printf("\t}\n");
printf("\n");
printf("\t//score from deck\n");
printf("%d%%\tfor (i = 0; i < state->discardCount[player]; i++)\n", suspiciousness[16]);
printf("\t{\n");
printf("%d%%\t\tif (state->deck[player][i] == curse) { score = score - 1; };\n", suspiciousness[17]);
printf("%d%%\t\tif (state->deck[player][i] == estate) { score = score + 1; };\n", suspiciousness[18]);
printf("%d%%\t\tif (state->deck[player][i] == duchy) { score = score + 3; };\n", suspiciousness[19]);
printf("%d%%\t\tif (state->deck[player][i] == province) { score = score + 6; };\n", suspiciousness[20]);
printf("%d%%\t\tif (state->deck[player][i] == great_hall) { score = score + 1; };\n", suspiciousness[21]);
printf("%d%%\t\tif (state->deck[player][i] == gardens) { score = score + ( fullDeckCount(player, 0, state) / 10 ); };\n", suspiciousness[22]);
printf("\t}\n");

}

/* verifies that the score recieved is correct.  returns 1 if correct and 0 otherwise*/
int scoreCorrect(int player, struct gameState *G, int testScore) {

	int totalCards = G->handCount[player] + G->deckCount[player] + G->discardCount[player];
	int cardArray[totalCards];

	int cardCount = 0;
	int i;
	for (i = 0; i < G->handCount[player]; i++) {
		cardArray[i] = G->hand[player][i];
		cardCount++;
	}
	for (i = 0; i < G->deckCount[player]; i++) {
		cardArray[cardCount++] = G->deck[player][i];
	}
	for (i = 0; i < G->discardCount[player]; i++) {
		cardArray[cardCount++] = G->discard[player][i];
	}
	assert(totalCards == cardCount);  //checking that i did the above code correctly

	//adding up the cards
	int score = 0;
	for (i = 0; i < totalCards; i++) {
		if (cardArray[i] == curse)
			score -= 1;
		if (cardArray[i] == estate)
			score += 1;
		if (cardArray[i] == duchy)
			score += 3;
		if (cardArray[i] == province)
			score += 6;
		if (cardArray[i] == gardens)
			score += floor(totalCards / 10);
		if (cardArray[i] == great_hall)
			score += 1;
	}

	if (score == testScore)
		return 1;
	else
		return 0;
}

/* Runs the code in score for and counts the number of times a line of code was run*/
int runScoreFor(int player, struct gameState *state) {
  int i; lastRunLines[0] = 1;
  int score = 0; lastRunLines[1] = 1;
  //score from hand
  for (i = 0; i < state->handCount[player]; i++)
    { 
      if (state->hand[player][i] == curse) { score = score - 1; lastRunLines[3] = 1; };
      if (state->hand[player][i] == estate) { score = score + 1;  lastRunLines[4] = 1; };
      if (state->hand[player][i] == duchy) { score = score + 3;  lastRunLines[5] = 1; };
      if (state->hand[player][i] == province) { score = score + 6; lastRunLines[6] = 1;};
      if (state->hand[player][i] == great_hall) { score = score + 1; lastRunLines[7] = 1;};
      if (state->hand[player][i] == gardens) { score = score + ( fullDeckCount(player, 0, state) / 10 ); lastRunLines[8] = 1;};
    }  lastRunLines[2] = 1; //for the for loop

  //score from discard
  for (i = 0; i < state->discardCount[player]; i++)
    { 
      if (state->discard[player][i] == curse) { score = score - 1; lastRunLines[10] = 1;};
      if (state->discard[player][i] == estate) { score = score + 1; lastRunLines[11] = 1;};
      if (state->discard[player][i] == duchy) { score = score + 3; lastRunLines[12] = 1;};
      if (state->discard[player][i] == province) { score = score + 6; lastRunLines[13] = 1;};
      if (state->discard[player][i] == great_hall) { score = score + 1; lastRunLines[14] = 1;};
      if (state->discard[player][i] == gardens) { score = score + ( fullDeckCount(player, 0, state) / 10 ); lastRunLines[15] = 1;};
    }  lastRunLines[9] = 1;  //for the for loop

  //score from deck
  for (i = 0; i < state->discardCount[player]; i++)
    { 
      if (state->deck[player][i] == curse) { score = score - 1; lastRunLines[17] = 1;};
      if (state->deck[player][i] == estate) { score = score + 1; lastRunLines[18] = 1;};
      if (state->deck[player][i] == duchy) { score = score + 3; lastRunLines[19] = 1;};
      if (state->deck[player][i] == province) { score = score + 6; lastRunLines[20] = 1;};
      if (state->deck[player][i] == great_hall) { score = score + 1; lastRunLines[21] = 1;};
      if (state->deck[player][i] == gardens) { score = score + ( fullDeckCount(player, 0, state) / 10 ); lastRunLines[22] = 1;};
    }  lastRunLines[16] = 1;  //for the for loop

   assert(score == scoreFor(player, state));  //verifying that the function here is the same as the function in dominion.c

  return score;

}

/*Runs the function with random values and updates the global variables based on the results */
void runRandomTest() {

	int i, p;
	struct gameState G;

	zeroLastRunLines();  //make the lastRunLines array all zero's

	//creating random gamestate
	for (i = 0; i < sizeof(struct gameState); i++) {
		((char *) &G)[i] = floor(Random() * 256);
	}

	G.numPlayers = floor(Random() * (MAX_PLAYERS - 1)) + 2;  //must have 2 to 4 players
	G.whoseTurn = floor(Random() * G.numPlayers );

	p = G.whoseTurn;

	sanitizeHandCards(&G);
	sanitizeDeckCards(&G);
	sanitizeDiscardCards(&G);
	
	//setting the counts low to increase variability in the successes and failures
	G.deckCount[p] = floor(Random() * 5);
	G.discardCount[p] = floor(Random() * 5);
	G.handCount[p] = floor(Random() * 5);

	int score = runScoreFor(G.whoseTurn, &G);
	if (scoreCorrect(G.whoseTurn, &G, score)) {
		successRuns++;
		addSuccess();
	} else {
		failRuns++;
		addFailures();
	}
}

int main(int argc, char **argv) {
  	SelectStream(2);
  	PutSeed(3);

	int i = 0;
	for (i = 0; i < NUM_RAND_TESTS; i++)
		runRandomTest();

	calculateSuspiciousness();
	printSuspiciousness();

	return 0;
	

}










